/*****************************************************
	SPI.h Joe Pardue September 8, 2010

	REVISION DETAILS IN SPI.H


******************************************************/

// I HATE LICENSES LIKE THIS >>BUT<< I've been told that without
// the license then the work is automatically copyrighted in my name
// since my purpose is to educate (and learn), I want the code to be 
// used by whoever wants to use it to learn something. If you like it, 
// then visit my website www.smileymicros.com and buy something.

/*
 *  BSD License
 *  -----------
 *
 *  Copyright (c) 2008, Smiley Micros, All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer. 
 *   
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution. 
 *   
 *  - Neither the name of the Smiley Micros nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission. 
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

// And to further cover my butt, let me add that if you use this software
// it will destroy whatever machine you use it on and kill anyone in a one 
// kilometer radius. So don't even consider using it for any reason whatsoever!

/*****************************************************
 	SPI.h provides headers for a library of SPI  
	functions for four types of SPI:

		Software SPI
		Hardware SPI
		USI SPI
		USART SPI
	
******************************************************/

#ifndef SPI_H
#define SPI_H

#include <avr/io.h>
#include "device.h" // defines device

/*****************************************************
******************************************************
	TODO: EXPLAIN USING MULTIPLE SPI OF VARYING TYPES
*******************************************************
******************************************************/

/*****************************************************
	Define number of SPI 
******************************************************/
#define SPI0
//#define SPI1
//#define SPIx // place holder

#if defined (SPI0)
/*****************************************************
******************************************************
	SPI0
*******************************************************
******************************************************/
void spi0_init_master(void);
uint8_t spi0_master_rw8(uint8_t to_slave);
uint16_t spi0_master_rw16(uint16_t to_slave);


void spi0_SS(void);
/*****************************************************
	Define SPI0 type
******************************************************/
#define SPI0_SOFT
//#define SPI0_HARD

/*****************************************************
	Declare SPI0 function
******************************************************/
//void spi0_init_master(void);
//void spi0_init_slave(void);
//void spi0_put_8(uint8_t);
//void spi0_put_16(uint16_t);
//uint8_t spi0_get_8(void);
//void spi0_wait(void);

//Now allow for SPI0 for each type


#if defined (SPI0_SOFT)
/*****************************************************
	Software SPI
******************************************************/
void spi0_soft_init_master(void);
uint8_t spi0_soft_master_rw8(uint8_t to_slave);
uint16_t spi0_soft_master_rw16(uint16_t to_slave);



// Define ports, pins, and data direction registers for set up
/*
#define mosi_port PORTB
#define mosi_port_pin  PORTB2
#define mosi_ddr  DDRB
#define mosi_port_pins PINB

#define miso_port PORTB
#define miso_port_pin  PORTB1
#define miso_ddr  DDRB
#define miso_port_pins PINB

#define sclk_port PORTB
#define sclk_port_pin PORTB3
#define sclk_ddr DDRB
//#define sclk_port PORTD
//#define sclk_port_pin PORTD7
//#define sclk_ddr DDRD

#define ss_port PORTB
#define ss_port_pin  PORTB0
#define ss_ddr  DDRB
*/

// Changed to fit Arduino hardware pin out for soft SPI test
#define mosi_port PORTB
#define mosi_port_pin  PORTB3
#define mosi_ddr  DDRB
#define mosi_port_pins PINB

#define miso_port PORTB
#define miso_port_pin  PORTB4
#define miso_ddr  DDRB
#define miso_port_pins PINB

#define sclk_port PORTB
#define sclk_port_pin PORTB5
#define sclk_ddr DDRB

#define ss_port PORTB
#define ss_port_pin  PORTB2
#define ss_ddr  DDRB



// Move bitwise operations to macros to 
// help keep folks heads from exploding
//#define spi_soft_clear_ss() ss_port &= ~(1<<ss_port_pin)
//#define spi_soft_set_ss() ss_port |= (1<<ss_port_pin)
#define spi0_clear_ss() ss_port &= ~(1<<ss_port_pin)	// RS added
#define spi0_set_ss() ss_port |= (1<<ss_port_pin)		// RS added
 
#define spi_soft_set_mosi_bit() mosi_port |= (1<<mosi_port_pin)
#define spi_soft_clear_mosi_bit() mosi_port &= ~(1<<mosi_port_pin)

#define is_bit_set(myVar, i) (!!(myVar & (1 << i)))

// Return the data pin state
uint8_t spi_soft_get_miso_bit(void);

// Return the data pin state
uint8_t spi_soft_get_miso_pin(void);

// Turn the clock line 0 to 1
void spi_soft_toggle_sclk(void);

// Initialize the SPI I/O pins
void spi_soft_setup_pins(void);


#elif defined (SPI0_HARD)
/*****************************************************
	Hardware SPI
******************************************************/
void spi0_hard_init_master(void);
uint8_t spi0_hard_master_rw8(uint8_t to_slave);
uint16_t spi0_hard_master_rw16(uint16_t to_slave);

#define spi_hard_clear_ss() (ss_hardware_port &= ~(1<<ss_hardware_pin))
#define spi_hard_set_ss() (ss_hardware_port |= (1<<ss_hardware_pin)) 


// Set up SPI hardware pins
//#if defined (ATmega169) | (Butterfly)
#if defined (Butterfly)
#define mosi_hardware_pin PORTB2
#define mosi_hardware_ddr DDB2
#define miso_hardware_pin PORTB3
#define miso_hardware_ddr DDB3
#define sclk_hardware_pin PORTB1
#define sclk_hardware_ddr DDB1

#define ss_hardware_port PORTB
#define ss_hardware_pin PORTB4
#define ss_hardware_ddr DDB4

#elif defined (Arduino) | (ATmega328)
#define mosi_hardware_pin PORTB3
#define mosi_hardware_ddr DDB3
#define miso_hardware_pin PORTB4
#define miso_hardware_ddr DDB4
#define sclk_hardware_pin PORTB5
#define sclk_hardware_ddr DDB5
#define ss_hardware_port PORTB
#define ss_hardware_pin PORTB2
#define ss_hardware_ddr DDB2

#elif defined (BeAVR40) || (ATmega644)
#define mosi_hardware_pin PB5
#define mosi_hardware_ddr DDB5
//#define miso_hardware_pin PB4
//#define miso_hardware_ddr DDB4
#define miso_hardware_pin PB6		// RS corrected per datasheet
#define miso_hardware_ddr DDB6		// RS corrected per datasheet
#define sclk_hardware_pin PB7
#define sclk_hardware_ddr DDB7
#define ss_hardware_port PORTB		// RS added
//#define ss_hardware_pin PB6
//#define ss_hardware_ddr DDB6
#define ss_hardware_pin PB4			// RS corrected per datasheet
#define ss_hardware_ddr DDB4		// RS corrected per datasheet

#else
	#error "no SPI pins declared"
#endif







#elif defined (SPI0_USI)
/*****************************************************
	USI SPI
******************************************************/


#elif defined (SPI0_USART)
/*****************************************************
	USART SPI
******************************************************/

//#else
//   #error "no SPI0 type declared"
#endif

//#else
//   #error "no SPI0 number declared"
#endif // SPI0




#if defined (SPI1)
/*****************************************************
******************************************************
	SPI1
*******************************************************
******************************************************/

/*****************************************************
	Define SPI1 type
******************************************************/
#define SPI1_SOFT
//#define SPI1_HARD
//#define SPI1_USI
//#define SPI1_USART

/*****************************************************
	Declare SPI1 function
******************************************************/
void spi1_initmaster(void);
//void spi1_initslave(void);
void spi1_put(uint8_t);
uint8_t spi1_get(void);
//void spi1_wait(void);

//Now allow for SPI1 for each type


#if defined (SPI1_SOFT)
/*****************************************************
	Software SPI
******************************************************/

void spi0_soft_init_master(void);
uint8_t spi0_soft_master_rw8(uint8_t to_slave);
uint16_t spi0_soft_master_rw16(uint16_t to_slave);

// Define ports, pins, and data direction registers for set up
#define mosi_port PORTB
#define mosi_port_pin  PORTB2
#define mosi_ddr  DDRB
#define mosi_port_pins PINB

#define miso_port PORTB
#define miso_port_pin  PORTB1
#define miso_ddr  DDRB
#define miso_port_pins PINB

#define sclk_port PORTD
#define sclk_port_pin PORTD7
#define sclk_ddr DDRD

#define ss_port PORTB
#define ss_port_pin  PORTB0
#define ss_ddr  DDRB


// Move bitwise operations to macros to 
// help keep folks heads from exploding
#define spi_soft_clear_ss() ss_port &= ~(1<<ss_port_pin)
#define spi_soft_set_ss() ss_port |= (1<<ss_port_pin) 
#define spi_soft_set_mosi_bit() mosi_port |= (1<<mosi_port_pin)
#define spi_soft_clear_mosi_bit() mosi_port &= ~(1<<mosi_port_pin)

#define is_bit_set(myVar, i) (!!(myVar & (1 << i)))

// Return the data pin state
uint8_t spi_soft_get_miso_bit(void);

// Return the data pin state
uint8_t spi_soft_get_miso_pin(void);

// Turn the clock line 0 to 1
void spi_soft_toggle_sclk(void);

// Initialize the SPI I/O pins
void spi_soft_setup_pins(void);


#elif defined (SPI1_HARD)
/*****************************************************
	Hardware SPI
******************************************************/


#elif defined (SPI1_USI)
/*****************************************************
	USI SPI
******************************************************/

// You have to set your own slave select
#define ss_port PORTD
#define ss_port_pin PORTD7
#define ss_ddr DDRD



#elif defined (SPI0_USART)
/*****************************************************
	USART SPI
******************************************************/

//#else
//   #error "no SPI1 type declared"
#endif

//#else
//   #error "no SPI1 number declared"
#endif // SPI1





#if defined (SPIx)
/*****************************************************
******************************************************
	SPIx
*******************************************************
******************************************************/

/*****************************************************
	Define SPIx type
******************************************************/
#define SPIx_SOFT
//#define SPIx_HARD
//#define SPIx_USI
//#define SPIx_USART

/*****************************************************
	Declare SPIx function
******************************************************/
void spix_initmaster(void);
//void spix_initslave(void);
void spix_put(uint8_t);
uint8_t spix_get(void);
//void spix_wait(void);

//Now allow for SPIx for each type


#if defined (SPIx_SOFT)
/*****************************************************
	Software SPx
******************************************************/

// Define ports, pins, and data direction registers for set up
#define mosi_port PORTB
#define mosi_port_pin  PORTB2
#define mosi_ddr  DDRB
#define mosi_port_pins PINB

#define miso_port PORTB
#define miso_port_pin  PORTB1
#define miso_ddr  DDRB
#define miso_port_pins PINB

#define sclk_port PORTD
#define sclk_port_pin PORTD7
#define sclk_ddr DDRD

#define ss_port PORTB
#define ss_port_pin  PORTB0
#define ss_ddr  DDRB


// Move bitwise operations to macros to 
// help keep folks heads from exploding
#define spi_soft_clear_ss() ss_port &= ~(1<<ss_port_pin)
#define spi_soft_set_ss() ss_port |= (1<<ss_port_pin) 
#define spi_soft_set_mosi_bit() mosi_port |= (1<<mosi_port_pin)
#define spi_soft_clear_mosi_bit() mosi_port &= ~(1<<mosi_port_pin)

#define is_bit_set(myVar, i) (!!(myVar & (1 << i)))

// Return the data pin state
uint8_t spi_soft_get_miso_bit(void);

// Return the data pin state
uint8_t spi_soft_get_miso_pin(void);

// Turn the clock line 0 to 1
void spi_soft_toggle_sclk(void);

// Initialize the SPI I/O pins
void spi_soft_setup_pins(void);


#elif defined (SPIx_HARD)
/*****************************************************
	Hardware SPI
******************************************************/


#elif defined (SPIx_USI)
/*****************************************************
	USI SPI
******************************************************/


#elif defined (SPIx_USART)
/*****************************************************
	USART SPI
******************************************************/

//#else
//   #error "no SPIx type declared"
#endif
//#else
//   #error "no SPIx number declared"
#endif // SPIx















//#define SPI_SOFT

//#if defined (SPI_SOFT)

/*****************************************************
******************************************************
	TODO: EXPLAIN SOFTWARE SPI
*******************************************************
******************************************************/

/*****************************************************
	Software SPI
******************************************************/

// Define ports, pins, and data direction registers for set up
/*#define mosi_port PORTB
#define mosi_port_pin  PORTB2
#define mosi_ddr  DDRB
#define mosi_port_pins PINB

#define miso_port PORTB
#define miso_port_pin  PORTB1
#define miso_ddr  DDRB
#define miso_port_pins PINB

#define sclk_port PORTD
#define sclk_port_pin PORTD7
#define sclk_ddr DDRD

#define ss_port PORTB
#define ss_port_pin  PORTB0
#define ss_ddr  DDRB


// Move bitwise operations to macros to 
// help keep folks heads from exploding
#define spi_soft_clear_ss() ss_port &= ~(1<<ss_port_pin)
#define spi_soft_set_ss() ss_port |= (1<<ss_port_pin) 
#define spi_soft_set_mosi_bit() mosi_port |= (1<<mosi_port_pin)
#define spi_soft_clear_mosi_bit() mosi_port &= ~(1<<mosi_port_pin)

#define is_bit_set(myVar, i) (!!(myVar & (1 << i)))

// Return the data pin state
uint8_t spi_soft_get_miso_bit(void);

// Return the data pin state
uint8_t spi_soft_get_miso_pin(void);

// Turn the clock line 0 to 1
void spi_soft_toggle_sclk(void);

// Initialize the SPI I/O pins
void spi_soft_setup_pins(void);


#elif defined (SPI_HARD)*/
/*****************************************************
******************************************************
	TODO: EXPLAIN SOFTWARE SPI
*******************************************************
******************************************************/

/*****************************************************
	Hardware SPI
******************************************************/


//#elif defined (SPI_USI)
/*****************************************************
******************************************************
	TODO: EXPLAIN USI SPI
*******************************************************
******************************************************/

/*****************************************************
	USI SPI
******************************************************/


//#elif defined (SPI_HARD)
/*****************************************************
******************************************************
	TODO: EXPLAIN HARDWARE SPI
*******************************************************
******************************************************/

/*****************************************************
	Hardware SPI
******************************************************/


//#elif defined (SPI_USART)
/*****************************************************
******************************************************
	TODO: EXPLAIN USART SPI
*******************************************************
******************************************************/

/*****************************************************
	USART SPI
******************************************************/

//#else
 //  #error "no SPI type declared"
//#endif




#endif // SPI_H
